import topology_engineer, traffic_engineer, network_controller, path_selector, traffic_history_reader, traffic_pb2
from aurora_network import *
import matplotlib.pyplot as plt
import pgfplotter_util

def check_for_empty_flows(aurora_network, traffic_snapshots):
	non_zero_flows = {}
	nblocks = aurora_network.get_num_blocks()
	timeseries = {(6,11) : [], (8,11) : [], (12, 11) : []}
	print("printing names to block id: {}".format(aurora_network.names_to_id_dict))
	for snapshot in traffic_snapshots:
		tm = aurora_network.get_traffic_matrix_from_traffic_snapshot(snapshot)
		for (i, j) in [(6, 11), (8,11), (12,11)]:
			timeseries[(i,j)].append(tm[i][j])
		for i in range(nblocks):
			for j in range(nblocks):
				if i != j:
					if tm[i][j] > 0:
						non_zero_flows[(i,j)] = True
	for key in timeseries.keys():
		fig = plt.figure()
		plt.title("i : {} to j : {}".format(key[0], key[1]))
		plt.plot(timeseries[key])
	plt.show()
	zero_flows = []
	for i in range(nblocks):
			for j in range(nblocks):
				if i != j and (i,j) not in non_zero_flows:
					zero_flows.append( (i, j, ) )	
	print("zeros flows : {}".format(zero_flows))
	print("fraction of zero flows to total flows: {}".format(float(len(zero_flows))/(nblocks * (nblocks - 1))))
	return zero_flows


def main(dcn_name, simulation_params, block_params, write_results_to_files, run_perfect_toe, run_perfect_te):

	topology_reconfig_num_snapshots = simulation_params["reconfig_frequency"] 
	topology_training_num_snapshots = simulation_params["training_num_snapshots"]
	traffic_update_num_snapshots = simulation_params["routing_update_frequency"] 
	traffic_training_num_snapshots = simulation_params["routing_training_length"] 
	numK_topol = simulation_params["num k topol"]
	numK_te = simulation_params["num k te"]

	# Step 1 : Read Traffic snapshots and also build the topologies
	print("Reading traffic snapshot history from files\nDCN name:{}\n".format(dcn_name))
	block_names_list, traffic_snapshots = traffic_history_reader.TrafficSnapshotReader(dcn_name).get_traffic_snapshots()
	traffic_snapshots_timestamps = [x.time_info.start_time for x in traffic_snapshots]
	print("Reading traffic files: COMPLETE.......\n")
	print("First snapshot timestamp: {}".format(traffic_snapshots_timestamps[0]))
	total_num_snapshots = len(traffic_snapshots)
	
	# Step 2 : Contruct the physical network itself
	aurora_network = AuroraNetwork(dcn_name, block_params, block_names_list)
	zero_flows = []
	#zero_flows = check_for_empty_flows(aurora_network, traffic_snapshots)
	# Step 4 : Construct the topology engineers and traffic engineers and path selectors
	# 4.1 : Path selector
	all_interblock_paths = path_selector.PathSelector(aurora_network, use_multihop=True).get_all_paths()
	
	# 4.2 : Topology engineer
	static_toe = topology_engineer.TopologyEngineer(aurora_network, total_num_snapshots)
	#static_toe = None
	#robust_toe = topology_engineer.RobustMultiTrafficTopologyEngineerImplementationV2(aurora_network, topology_training_num_snapshots,
	#																				 topology_reconfig_num_snapshots, all_interblock_paths, 
	#																				 traffic_snapshots, numK)
	robust_toe = topology_engineer.RobustMultiTrafficTopologyEngineer(aurora_network, topology_training_num_snapshots,
																					 topology_reconfig_num_snapshots, all_interblock_paths, 
																					 traffic_snapshots, numK_topol, ignore_flows=zero_flows)
	robust_toe.cache_logical_topologies(round_to_integer=True)
	#robust_toe = None
	ave_toe = topology_engineer.HistoricalAveTrafficTopologyEngineer(aurora_network, topology_training_num_snapshots,
																					 topology_reconfig_num_snapshots, all_interblock_paths, 
																					 traffic_snapshots)
	#ave_toe.cache_logical_topologies(round_to_integer=True)
	ave_toe = None
	max_toe = topology_engineer.HistoricalMaxTrafficTopologyEngineer(aurora_network, topology_training_num_snapshots,
																					 topology_reconfig_num_snapshots, all_interblock_paths, 
																					 traffic_snapshots)
	#max_toe.cache_logical_topologies(round_to_integer=True)
	max_toe = None
	perfect_toe = None
	if run_perfect_toe:
		perfect_toe = topology_engineer.IdealTopologyEngineer(aurora_network, all_interblock_paths, traffic_snapshots)
		#perfect_toe.cache_logical_topologies()
	# 4.3 : Traffic engineer
	# ecmp = traffic_engineer.TrafficEngineer(aurora_network, all_interblock_paths)
	wcmp = traffic_engineer.WCMPTrafficEngineer(aurora_network, all_interblock_paths)
	wcmp = None
	#wcmp = None
	oblivious_routing = traffic_engineer.ObliviousRouting(aurora_network, all_interblock_paths)
	oblivious_routing = None
	robust_te = traffic_engineer.RobustMultiClusterTrafficEngineer(aurora_network, all_interblock_paths, traffic_update_num_snapshots, traffic_training_num_snapshots, numK_te, ignore_flows=zero_flows)
	robust_te = None
	robust_weighted_te = traffic_engineer.RobustMultiClusterScaleUpWeightedTrafficEngineer(aurora_network, all_interblock_paths, traffic_update_num_snapshots, traffic_training_num_snapshots, numK_te, ignore_flows=zero_flows)
	#robust_weighted_te = None
	robust_weighted_heuristic_te = traffic_engineer.RobustMultiClusterScaleUpWeightedTrafficEngineerHeuristic(aurora_network, all_interblock_paths, traffic_update_num_snapshots, traffic_training_num_snapshots, numK_te, ignore_flows=zero_flows)
	robust_weighted_heuristic_te = None
	ave_te = traffic_engineer.HistoricalAveTrafficEngineer(aurora_network, all_interblock_paths, traffic_update_num_snapshots, traffic_training_num_snapshots)
	ave_te = None
	max_te = traffic_engineer.HistoricalMaxTrafficEngineer(aurora_network, all_interblock_paths, traffic_update_num_snapshots, traffic_training_num_snapshots)
	max_te = None
	perfect_te = None
	if run_perfect_te:
		perfect_te = traffic_engineer.IdealTrafficEngineer(aurora_network, all_interblock_paths)

	# Step 5 : Construct the various network controllers, each with a different static and dynamic topology engineer
	# Static network controllers with different TE schemes
	static_toe_wcmp_te_netcontroller = network_controller.NetworkController(aurora_network, static_toe, wcmp, len(traffic_snapshots))
	static_toe_robust_te_netcontroller = network_controller.NetworkController(aurora_network, static_toe, robust_te, len(traffic_snapshots))
	static_toe_robust_weighted_te_netcontroller = network_controller.NetworkController(aurora_network, static_toe, robust_weighted_te, len(traffic_snapshots))
	static_toe_robust_weighted_heuristic_te_netcontroller = network_controller.NetworkController(aurora_network, static_toe, robust_weighted_heuristic_te, len(traffic_snapshots))
	static_toe_ave_te_netcontroller = network_controller.NetworkController(aurora_network, static_toe, ave_te, len(traffic_snapshots))
	static_toe_max_te_netcontroller = network_controller.NetworkController(aurora_network, static_toe, max_te, len(traffic_snapshots))
	static_toe_perfect_te_netcontroller = network_controller.NetworkController(aurora_network, static_toe, perfect_te, len(traffic_snapshots))

	# Robust ToE network controllers with different TE schemes
	robust_toe_wcmp_te_netcontroller = network_controller.NetworkController(aurora_network, robust_toe, wcmp, len(traffic_snapshots))
	robust_toe_robust_te_netcontroller = network_controller.NetworkController(aurora_network, robust_toe, robust_te, len(traffic_snapshots))
	robust_toe_robust_weighted_te_netcontroller = network_controller.NetworkController(aurora_network, robust_toe, robust_weighted_te, len(traffic_snapshots))
	robust_toe_robust_weighted_heuristic_te_netcontroller = network_controller.NetworkController(aurora_network, robust_toe, robust_weighted_heuristic_te, len(traffic_snapshots))
	robust_toe_ave_te_netcontroller = network_controller.NetworkController(aurora_network, robust_toe, ave_te, len(traffic_snapshots))
	robust_toe_max_te_netcontroller = network_controller.NetworkController(aurora_network, robust_toe, max_te, len(traffic_snapshots))
	robust_toe_perfect_te_netcontroller = network_controller.NetworkController(aurora_network, robust_toe, perfect_te, len(traffic_snapshots))
	
	ave_toe_ave_te_netcontroller = network_controller.NetworkController(aurora_network, ave_toe, ave_te, len(traffic_snapshots))
	ave_toe_perfect_te_netcontroller = network_controller.NetworkController(aurora_network, ave_toe, perfect_te, len(traffic_snapshots))
	max_toe_max_te_netcontroller = network_controller.NetworkController(aurora_network, max_toe, max_te, len(traffic_snapshots))
	max_toe_perfect_te_netcontroller = network_controller.NetworkController(aurora_network, max_toe, perfect_te, len(traffic_snapshots))

	static_toe_oblivious_routing_netcontroller = network_controller.NetworkController(aurora_network, static_toe, oblivious_routing, len(traffic_snapshots))
	robust_toe_oblivious_routing_netcontroller = network_controller.NetworkController(aurora_network, robust_toe, oblivious_routing, len(traffic_snapshots))
	#ave_toe_ave_te_netcontroller = network_controller.NetworkController(aurora_network, None, None, len(traffic_snapshots))
	#max_toe_max_te_netcontroller = network_controller.NetworkController(aurora_network, None, None, len(traffic_snapshots))

	# Perfect ToE, only makes sense with perfect TE (performance limit)
	perfect_toe_perfect_te_netcontroller = network_controller.NetworkController(aurora_network, perfect_toe, perfect_te, len(traffic_snapshots))


	# given the traffic snapshots and block names of the already built topology engineered topology, build the static topology
	print("\n########################################################################")
	print("Preamble / setup stage completed")
	print("Initializing evaluations")
	print("########################################################################\n")
	## Step 6 : MAIN SIMULATIONS START 
	
	static_toe_wcmp_te_perf = static_toe_wcmp_te_netcontroller.evaluate_performance(traffic_snapshots)
	static_toe_robust_te_perf = static_toe_robust_te_netcontroller.evaluate_performance(traffic_snapshots)
	static_toe_robust_weighted_te_perf = static_toe_robust_weighted_te_netcontroller.evaluate_performance(traffic_snapshots)
	static_toe_robust_weighted_heuristic_te_perf = static_toe_robust_weighted_heuristic_te_netcontroller.evaluate_performance(traffic_snapshots)
	static_toe_ave_te_perf = static_toe_ave_te_netcontroller.evaluate_performance(traffic_snapshots)
	static_toe_max_te_perf = static_toe_max_te_netcontroller.evaluate_performance(traffic_snapshots)
	static_toe_perfect_te_perf = static_toe_perfect_te_netcontroller.evaluate_performance(traffic_snapshots)

	robust_toe_wcmp_te_perf = robust_toe_wcmp_te_netcontroller.evaluate_performance(traffic_snapshots)
	robust_toe_robust_te_perf = robust_toe_robust_te_netcontroller.evaluate_performance(traffic_snapshots)
	robust_toe_robust_weighted_te_perf = robust_toe_robust_weighted_te_netcontroller.evaluate_performance(traffic_snapshots)
	robust_toe_robust_weighted_heuristic_te_perf = robust_toe_robust_weighted_heuristic_te_netcontroller.evaluate_performance(traffic_snapshots)
	robust_toe_ave_te_perf = robust_toe_ave_te_netcontroller.evaluate_performance(traffic_snapshots)
	robust_toe_max_te_perf = robust_toe_max_te_netcontroller.evaluate_performance(traffic_snapshots)
	robust_toe_perfect_te_perf = robust_toe_perfect_te_netcontroller.evaluate_performance(traffic_snapshots)

	ave_toe_ave_te_perf = ave_toe_ave_te_netcontroller.evaluate_performance(traffic_snapshots)
	ave_toe_perfect_te_perf = ave_toe_perfect_te_netcontroller.evaluate_performance(traffic_snapshots)
	max_toe_max_te_perf = max_toe_max_te_netcontroller.evaluate_performance(traffic_snapshots)
	max_toe_perfect_te_perf = max_toe_perfect_te_netcontroller.evaluate_performance(traffic_snapshots)


	perfect_toe_perfect_te_perf = perfect_toe_perfect_te_netcontroller.evaluate_performance(traffic_snapshots)


	static_toe_oblivious_routing_perf = static_toe_oblivious_routing_netcontroller.evaluate_performance(traffic_snapshots)
	robust_toe_oblivious_routing_perf = robust_toe_oblivious_routing_netcontroller.evaluate_performance(traffic_snapshots)

	# 6.0 : Disregard some of the initial snapshots because ToE could not be set up yet
	starting_index = max(topology_training_num_snapshots, traffic_training_num_snapshots)
	#traffic_snapshots_timestamps = traffic_snapshots_timestamps[starting_index : ]
	

	# Write to file
	if write_results_to_files:
		# Write performance to file
		if static_toe_wcmp_te_perf is not None:
			pgfplotter_util.export_timeseries_performance("results/{}/timeseries_{}_{}".format(dcn_name, static_toe.get_filename_param(), wcmp.get_filename_param()), 
															traffic_snapshots_timestamps, 
															static_toe_wcmp_te_perf)
		if static_toe_oblivious_routing_perf is not None:
			pgfplotter_util.export_timeseries_performance("results/{}/timeseries_{}_{}".format(dcn_name, static_toe.get_filename_param(), oblivious_routing.get_filename_param()), 
															traffic_snapshots_timestamps, 
															static_toe_oblivious_routing_perf)
		if static_toe_perfect_te_perf is not None:
			pgfplotter_util.export_timeseries_performance("results/{}/timeseries_{}_{}".format(dcn_name, static_toe.get_filename_param(), perfect_te.get_filename_param()), 
															traffic_snapshots_timestamps, 
															static_toe_perfect_te_perf)
		if static_toe_robust_te_perf is not None:
			pgfplotter_util.export_timeseries_performance("results/{}/timeseries_{}_{}".format(dcn_name, static_toe.get_filename_param(), robust_te.get_filename_param()), 
															traffic_snapshots_timestamps[traffic_training_num_snapshots : ], 
															static_toe_robust_te_perf[traffic_training_num_snapshots : ])
		if static_toe_robust_weighted_te_perf is not None:
			pgfplotter_util.export_timeseries_performance("results/{}/timeseries_{}_{}".format(dcn_name, static_toe.get_filename_param(), robust_weighted_te.get_filename_param()), 
															traffic_snapshots_timestamps[traffic_training_num_snapshots : ], 
															static_toe_robust_weighted_te_perf[traffic_training_num_snapshots : ])
		if static_toe_robust_weighted_heuristic_te_perf is not None:
			pgfplotter_util.export_timeseries_performance("results/{}/timeseries_{}_{}".format(dcn_name, static_toe.get_filename_param(), robust_weighted_heuristic_te.get_filename_param()), 
															traffic_snapshots_timestamps[traffic_training_num_snapshots : ], 
															static_toe_robust_weighted_heuristic_te_perf[traffic_training_num_snapshots : ])
		if static_toe_ave_te_perf is not None:
			pgfplotter_util.export_timeseries_performance("results/{}/timeseries_{}_{}".format(dcn_name, static_toe.get_filename_param(), ave_te.get_filename_param()), 
															traffic_snapshots_timestamps[traffic_training_num_snapshots : ], 
															static_toe_ave_te_perf[traffic_training_num_snapshots : ])
		if static_toe_max_te_perf is not None:
			pgfplotter_util.export_timeseries_performance("results/{}/timeseries_{}_{}".format(dcn_name, static_toe.get_filename_param(), max_te.get_filename_param()), 
															traffic_snapshots_timestamps[traffic_training_num_snapshots : ], 
															static_toe_max_te_perf[traffic_training_num_snapshots : ])
		if robust_toe_wcmp_te_perf is not None:
			pgfplotter_util.export_timeseries_performance("results/{}/timeseries_{}_{}".format(dcn_name, robust_toe.get_filename_param(), wcmp.get_filename_param()), 
															traffic_snapshots_timestamps[topology_training_num_snapshots : ], 
															robust_toe_wcmp_te_perf[topology_training_num_snapshots : ])
		if robust_toe_oblivious_routing_perf is not None:
			pgfplotter_util.export_timeseries_performance("results/{}/timeseries_{}_{}".format(dcn_name, robust_toe.get_filename_param(), oblivious_routing.get_filename_param()), 
															traffic_snapshots_timestamps[topology_training_num_snapshots : ], 
															robust_toe_oblivious_routing_perf[topology_training_num_snapshots : ])
		if robust_toe_perfect_te_perf is not None:
			pgfplotter_util.export_timeseries_performance("results/{}/timeseries_{}_{}".format(dcn_name, robust_toe.get_filename_param(), perfect_te.get_filename_param()), 
															traffic_snapshots_timestamps[topology_training_num_snapshots : ], 
															robust_toe_perfect_te_perf[topology_training_num_snapshots : ])
		if robust_toe_robust_te_perf is not None:
			pgfplotter_util.export_timeseries_performance("results/{}/timeseries_{}_{}".format(dcn_name, robust_toe.get_filename_param(), robust_te.get_filename_param()), 
															traffic_snapshots_timestamps[starting_index : ], 
															robust_toe_robust_te_perf[starting_index : ])
		if robust_toe_robust_weighted_te_perf is not None:
			pgfplotter_util.export_timeseries_performance("results/{}/timeseries_{}_{}".format(dcn_name, robust_toe.get_filename_param(), robust_weighted_te.get_filename_param()), 
															traffic_snapshots_timestamps[starting_index : ], 
															robust_toe_robust_weighted_te_perf[starting_index : ])
		if robust_toe_robust_weighted_heuristic_te_perf is not None:
			pgfplotter_util.export_timeseries_performance("results/{}/timeseries_{}_{}".format(dcn_name, robust_toe.get_filename_param(), robust_weighted_heuristic_te.get_filename_param()), 
															traffic_snapshots_timestamps[starting_index : ], 
															robust_toe_robust_weighted_heuristic_te_perf[starting_index : ])
		if robust_toe_ave_te_perf is not None:
			pgfplotter_util.export_timeseries_performance("results/{}/timeseries_{}_{}".format(dcn_name, robust_toe.get_filename_param(), ave_te.get_filename_param()), 
															traffic_snapshots_timestamps[starting_index : ], 
															robust_toe_ave_te_perf[starting_index : ])
		if robust_toe_max_te_perf is not None:
			pgfplotter_util.export_timeseries_performance("results/{}/timeseries_{}_{}".format(dcn_name, robust_toe.get_filename_param(), max_te.get_filename_param()), 
															traffic_snapshots_timestamps[starting_index : ], 
															robust_toe_max_te_perf[starting_index : ])
		if ave_toe_ave_te_perf is not None:
			pgfplotter_util.export_timeseries_performance("results/{}/timeseries_{}_{}".format(dcn_name, ave_toe.get_filename_param(), ave_te.get_filename_param()), 
															traffic_snapshots_timestamps[starting_index : ], 
															ave_toe_ave_te_perf[starting_index : ])
		if ave_toe_perfect_te_perf is not None:
			pgfplotter_util.export_timeseries_performance("results/{}/timeseries_{}_{}".format(dcn_name, ave_toe.get_filename_param(), perfect_te.get_filename_param()), 
															traffic_snapshots_timestamps[starting_index : ], 
															ave_toe_perfect_te_perf[starting_index : ])
		if max_toe_max_te_perf is not None:
			pgfplotter_util.export_timeseries_performance("results/{}/timeseries_{}_{}".format(dcn_name, max_toe.get_filename_param(), max_te.get_filename_param()), 
															traffic_snapshots_timestamps[starting_index : ], 
															max_toe_max_te_perf[starting_index : ])

		if max_toe_max_te_perf is not None:
			pgfplotter_util.export_timeseries_performance("results/{}/timeseries_{}_{}".format(dcn_name, max_toe.get_filename_param(), max_te.get_filename_param()), 
															traffic_snapshots_timestamps[starting_index : ], 
															max_toe_max_te_perf[starting_index : ])
		if perfect_toe_perfect_te_perf is not None:
			pgfplotter_util.export_timeseries_performance("results/{}/timeseries_{}_{}".format(dcn_name, perfect_toe.get_filename_param(), perfect_te.get_filename_param()), 
															traffic_snapshots_timestamps, 
															perfect_toe_perfect_te_perf)	



	# 6.1 : Obtain the ave hop count metrics
	ahc_static_toe_wcmp_te = sorted([x[3] for x in static_toe_wcmp_te_perf])
	#ahc_static_toe_perfect_te = sorted([x[3] for x in static_toe_perfect_te_perf])
	ahc_static_toe_robust_te = sorted([x[3] for x in static_toe_robust_te_perf[starting_index : ]])
	ahc_static_toe_robust_weighted_te = sorted([x[3] for x in static_toe_robust_weighted_te_perf[starting_index : ]])
	perf_static_toe_robust_te_sorted_by_ahc = sorted(static_toe_robust_te_perf[starting_index : ], key=lambda x: x[3])
	ahc_robust_toe_wcmp_te = sorted([x[3] for x in robust_toe_wcmp_te_perf])
	#ahc_robust_toe_perfect_te = sorted([x[3] for x in robust_toe_perfect_te_perf])
	ahc_robust_toe_robust_te = sorted([x[3] for x in robust_toe_robust_te_perf[starting_index : ]])
	ahc_robust_toe_robust_weighted_te = sorted([x[3] for x in robust_toe_robust_weighted_te_perf[starting_index : ]])
	perf_robust_toe_robust_te_sorted_by_ahc = sorted(robust_toe_robust_te_perf[starting_index : ], key=lambda x: x[3])
	#ahc_ave_toe_ave_te = sorted([x[3] for x in ave_toe_ave_te_perf[starting_index : ]])
	#ahc_max_toe_max_te = sorted([x[3] for x in max_toe_max_te_perf[starting_index : ]])
	ahc_static_toe_wcmp_te = sorted([x[3] for x in static_toe_wcmp_te_perf[starting_index : ]])
	ahc_robust_toe_wcmp_te = sorted([x[3] for x in robust_toe_wcmp_te_perf[starting_index : ]])

	# 6.2 : Obtain the MLU metrics
	#mlu_static_toe_wcmp_te = sorted([x[0] for x in static_toe_wcmp_te_perf])
	#mlu_static_toe_perfect_te = sorted([x[0] for x in static_toe_perfect_te_perf])
	mlu_static_toe_robust_te = sorted([x[0] for x in static_toe_robust_te_perf[starting_index : ]])
	mlu_static_toe_robust_weighted_te = sorted([x[0] for x in static_toe_robust_weighted_te_perf[starting_index : ]])
	perf_static_toe_robust_te_sorted_by_mlu = sorted(static_toe_robust_te_perf[starting_index : ], key=lambda x: x[0])
	#mlu_robust_toe_wcmp_te = sorted([x[0] for x in robust_toe_wcmp_te_perf])
	#mlu_robust_toe_perfect_te = sorted([x[0] for x in robust_toe_perfect_te_perf])
	mlu_robust_toe_robust_te = sorted([x[0] for x in robust_toe_robust_te_perf[starting_index : ]])
	mlu_robust_toe_robust_weighted_te = sorted([x[0] for x in robust_toe_robust_weighted_te_perf[starting_index : ]])
	#mlu_ave_toe_ave_te = sorted([x[0] for x in ave_toe_ave_te_perf[starting_index : ]])
	#mlu_max_toe_max_te = sorted([x[0] for x in max_toe_max_te_perf[starting_index : ]])
	mlu_static_toe_wcmp_te = sorted([x[0] for x in static_toe_wcmp_te_perf[starting_index : ]])
	mlu_robust_toe_wcmp_te = sorted([x[0] for x in robust_toe_wcmp_te_perf[starting_index : ]])
	perf_robust_toe_robust_te_sorted_by_mlu = sorted(robust_toe_robust_te_perf[starting_index : ], key=lambda x: x[0])


	print("worst case mlu timestamp for robust toe: {} val: {}".format(perf_robust_toe_robust_te_sorted_by_mlu[-1][4], perf_robust_toe_robust_te_sorted_by_mlu[-1][0]))
	print("worst case mlu timestamp for static toe: {} val: {}".format(perf_static_toe_robust_te_sorted_by_mlu[-1][4], perf_static_toe_robust_te_sorted_by_mlu[-1][0]))



	fig = plt.figure()
	#legends = ["static uniform mesh - wcmp", "static uniform mesh - robust multi traffic", "static uniform mesh - perfect"]
	#legends += ["robust ToE - wcmp", "robust ToE - robust multi traffic", "robust ToE - perfect"]
	#plt.plot(ahc_static_toe_wcmp_te)
	legends = ["static - multi TE", "static - multi TE weighted", "ToE - multi TE", "ToE - multi TE weighted", "Ave ToE - TE", "Max ToE - TE", "static - WCMP", "ToE - WCMP"]
	plt.plot(ahc_static_toe_robust_te)
	plt.plot(ahc_static_toe_robust_weighted_te)
	#plt.plot(ahc_static_toe_perfect_te)
	#plt.plot(ahc_robust_toe_wcmp_te)
	plt.plot(ahc_robust_toe_robust_te)
	plt.plot(ahc_robust_toe_robust_weighted_te)
	#plt.plot(ahc_ave_toe_ave_te)
	#plt.plot(ahc_max_toe_max_te)
	plt.plot(ahc_static_toe_wcmp_te)
	plt.plot(ahc_robust_toe_wcmp_te)
	#plt.plot(ahc_robust_toe_perfect_te)
	plt.legend(legends)
	plt.xlabel("Time Index")
	plt.title("Ave. Hop Count (Interpod)")

	fig = plt.figure()
	#legends = ["static uniform mesh - wcmp", "static uniform mesh - robust multi traffic", "static uniform mesh - perfect"]
	#legends += ["robust ToE - wcmp", "robust ToE - robust multi traffic", "robust ToE - perfect"]
	legends = ["static - multi TE", "static - multi TE weighted", "ToE - multi TE", "ToE - multi TE weighted", "Ave ToE - TE", "Max ToE - TE", "static - WCMP", "ToE - WCMP"]
	#plt.plot(mlu_static_toe_wcmp_te)
	plt.plot(mlu_static_toe_robust_te)
	plt.plot(mlu_static_toe_robust_weighted_te)
	#plt.plot(mlu_static_toe_perfect_te)
	#plt.plot(mlu_robust_toe_wcmp_te)
	plt.plot(mlu_robust_toe_robust_te)
	plt.plot(mlu_robust_toe_robust_weighted_te)
	#plt.plot(mlu_ave_toe_ave_te)
	#plt.plot(mlu_max_toe_max_te)
	plt.plot(mlu_static_toe_wcmp_te)
	plt.plot(mlu_robust_toe_wcmp_te)
	#plt.plot(mlu_robust_toe_perfect_te)
	plt.ylim(ymin=0)
	plt.legend(legends)
	plt.xlabel("Time Index")
	plt.title("MLU")
	plt.show()


	#static_toe_wcmp_te_netcontroller
	#static_toe_perfect_te_netcontroller
	#static_toe_robust_te_netcontroller
	#robust_toe_wcmp_te_netcontroller
	#robust_toe_perfect_te_netcontroller
	#robust_toe_robust_te_netcontroller
	return

if __name__ == "__main__":
	print("\n\n")
	print("############################################")
	print("# Simulation begins")
	print("############################################")

	### Stipulating the simulation parameters here
	#dcn_name = "ju2_dls03"
	#dcn_name = "ju2_dls03"
	dcn_name = "ju1_dls08"
	#reconfig_frequency = 2 * 7 * 24 * 12
	reconfig_frequency = 2 * 7 * 24 * 12
	training_num_snapshots = 7 * 24 * 12
	routing_update_num_snapshots = 2 * 24 * 12
	routing_training_num_snapshots = 2 * 24 * 12
	numK_topol = 4
	numK_te = 1
	write_results_to_files = True # decides if we write results to file
	run_perfect_te = False # decides if we write results to file
	run_perfect_toe = False # decides if we write results to file
	

	superblock_num_links = 256
	border_router_num_links = 256
	superblock_link_capacity = 100
	border_router_link_capacity = 100

	simulation_params = {}
	simulation_params["reconfig_frequency"] = reconfig_frequency
	simulation_params["training_num_snapshots"] = training_num_snapshots
	simulation_params["routing_update_frequency"] = routing_update_num_snapshots
	simulation_params["routing_training_length"] = routing_training_num_snapshots
	simulation_params["num k topol"] = numK_topol
	simulation_params["num k te"] = numK_te

	block_params = {BlockType.SUPERBLOCK : {}, BlockType.BORDER_ROUTER : {}}
	block_params[BlockType.SUPERBLOCK]["link capacity"] = float(superblock_link_capacity)
	block_params[BlockType.SUPERBLOCK]["num links"] = float(superblock_num_links)
	block_params[BlockType.BORDER_ROUTER]["link capacity"] = float(border_router_link_capacity) # in gbps
	block_params[BlockType.BORDER_ROUTER]["num links"] = float(border_router_num_links)

	main(dcn_name, simulation_params, block_params, write_results_to_files, run_perfect_toe, run_perfect_te)
	print("############################################")
	print("# Simulation completes")
	print("############################################")
	print("\n\n")
